#ifndef _PARSER
#define _PARSER

#include"programnode.h"
#include"variablenode.h" //x
#include"integernode.h" // i
#include"operatornode.h" //@
#include"lambdanode.h" 
// FunctionNode f
// ChoiceNode ?
// ApplicatioNode a
// ProgramNode 

#include <iostream>
#include <string>
#include <map>

using std::pair;
//using namespace std;


class LambdaParser{
	
	ExpressionNode* parseExpression(std::istream &is){
		
		std::string str;
		is >> str;
		if (str == "@"){	
			 
				std::string op;
				is >> op;
				ExpressionNode* fst = parseExpression(is);				
				ExpressionNode* snd = parseExpression(is);
				if (op == "+") return new OperatorNode(_PLUS, fst,snd);				
				if (op == "-") return new OperatorNode( _MINUS, fst,snd);				
				if (op == "*") return new OperatorNode(_MULT, fst,snd);				
				if (op == "/") return new OperatorNode(_DIV, fst,snd);				
				if (op == "%") return new OperatorNode(_MOD, fst,snd);				
				if (op == "==") return new OperatorNode(_EQUAL, fst,snd);				
				if (op == "<") return new OperatorNode(_LT, fst,snd);				
				if (op == ">") return new OperatorNode(_GT, fst,snd);				
				if (op == "<=") return new OperatorNode(_LE, fst,snd);				
				if (op == ">=") return new OperatorNode(_GE, fst,snd);
				
		}
		if (str == "?"){
				ExpressionNode* fst = parseExpression(is);				
				ExpressionNode* snd = parseExpression(is);
				ExpressionNode* thrd = parseExpression(is);
				return new ChoiceNode(fst, snd, thrd);
		}
		if (str == "a"){
				ExpressionNode* fst = parseExpression(is);				
				ExpressionNode* snd = parseExpression(is);
				return new ApplicationNode(fst,snd);
		}
		if (str == "f")	{
				std::string var;
				is >> var;
				ExpressionNode* fst = parseExpression(is);				
				return new FunctionNode(VariableNode(var), fst);
		}
		if (str == "x")	{
				std::string var;
				is >> var;
				return new VariableNode(var);
		}
		if (str == "!")	{
				int val;
				is >> val;
				return new IntegerNode(val);
		}
		std::cout<<"nothing"<<std::endl;
		return 0;
		
	}

	
	
	ProgramNode* parseProgram(std::istream &is){
		
		std::string str;
		is >> str;
		if (str == ";") return 0;
		VariableNode var(str);
		ExpressionNode* expr = parseExpression(is);

		ProgramNode* p = new ProgramNode(var, expr);
		return p->append(parseProgram(is));
	}

	public:
		
	pair<ProgramNode*,ExpressionNode*> parse(std::istream &is){
		
		ProgramNode* pn = parseProgram(is);
		ExpressionNode* pe = parseExpression(is);
		return pair<ProgramNode*,ExpressionNode*>(pn,pe);		
	}

};

#endif
